package com.howie.hmvc.scanner;

import java.io.File;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 类扫描器
 * @author dhz
 */
public class ClassScanner {

	/**
	 * 从指定的包中扫描类
	 * @param packge
	 * @throws Exception 
	 */
	public static List<Class<?>> scannerPackge(String packge) throws Exception{
		List<Class<?>> list = new ArrayList<Class<?>>();
		String path = packge.replaceAll("\\.|\\\\","/");
		path = path.replaceAll("^/*|/*$","");
		packge = path.replace("/",".");
		//扫描类
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        Enumeration<URL> resources = classLoader.getResources(path);
        while (resources.hasMoreElements()) {
        	URL url = resources.nextElement();
        	String protocol = url.getProtocol();
            //file协议
            if("file".equalsIgnoreCase(protocol)){
            	List<Class<?>> dirList = scanClassesFromDir(new File(URLDecoder.decode(url.getFile(),"UTF-8")),packge);
            	list.addAll(dirList);
            }
            //jar协议
            else if("jar".equalsIgnoreCase(protocol)){
            	List<Class<?>> dirList = scanClassesFromJar(url,path);
            	list.addAll(dirList);
            }
            //vfs协议，如jboss就是这个协议
            /*else if("vfs".equalsIgnoreCase(protocol)){
            	
            }*/
            //未知协议
            else{
            	throw new Exception("扫描类失败，发现了未知协议：" + protocol);
            }
        }
        return list;
	}
	
	/**
	 * 从指定的包数组中扫描类
	 * @param packges
	 * @throws Exception 
	 */
	public static List<Class<?>> scannerPackges(String[] packges) throws Exception{
		List<Class<?>> list = new ArrayList<Class<?>>();
		for(String packge : packges){
			List<Class<?>> packgeList = scannerPackge(packge);
			list.addAll(packgeList);
		}
		return list;
	}
	
	/*
	 * 在指定目录下递归扫描类文件
	 * @param directory
	 * @param packageName
	 * @throws Exception
	 */
	private static List<Class<?>> scanClassesFromDir(File directory,String packageName)throws Exception {
		List<Class<?>> list = new ArrayList<Class<?>>();
    	if(directory.exists()){
    		for(File file : directory.listFiles()){
    			String fileName = file.getName();
    			if(file.isDirectory()) {
    				List<Class<?>> subList = scanClassesFromDir(file,packageName + "." + fileName);
    				list.addAll(subList);
    			} else if(fileName.endsWith(".class") && !fileName.contains("$")) {
    				Class<?> cls = Class.forName(packageName + '.' + fileName.substring(0, fileName.length() - 6));
    				list.add(cls);
    			}
    		}
        }
    	return list;
	}
	
	/*
	 * 扫描的包在jar包中
	 * 2012-11-4
	 * @param url
	 * @param pack
	 * @throws IOException
	 */
	private static List<Class<?>> scanClassesFromJar(URL url,String pack) throws Exception {
		List<Class<?>> list = new ArrayList<Class<?>>();
		JarURLConnection jarUrlConn = (JarURLConnection) url.openConnection();
		JarFile jarFile = jarUrlConn.getJarFile();
		Enumeration<JarEntry> entries = jarFile.entries();
		String packCp = pack + "/";
		while (entries.hasMoreElements()) {
			JarEntry entry = entries.nextElement();
			String clsPath = entry.getName();
			if(clsPath.startsWith(packCp) && clsPath.endsWith(".class") && !clsPath.contains("$")){
				clsPath = clsPath.substring(0,clsPath.length() - 6).replace("/",".");
				Class<?> cls = Class.forName(clsPath);
				list.add(cls);
			}
		}
		return list;
	}
	
}
